package com.example.ftpclient;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import java.io.*;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.util.concurrent.CountDownLatch;

/**
 * 为ftp网络协议提供请求方法
 */
public class FTPClientGetFileUtils {

    private FTPClient ftpClient;

    public FTPClient getFtpClient() {
        return ftpClient;
    }

    public void setFtpClient(FTPClient ftpClient) {
        this.ftpClient = ftpClient;
    }

    FTPClientGetFileUtils(FTPClient ftpClient){
        setFtpClient(ftpClient);
    }

    public static FTPClientGetFileUtils create(String host, String username, String password){
        synchronized (FTPClientGetFileUtils.class){
            FTPClient ftp = new FTPClient();
            int replyCount=5;
            while (replyCount-->0){
                try {
                    ftp.connect(host);
                    ftp.login(username, password);
                    ftp.enterLocalPassiveMode();
//                    ftp.enterLocalActiveMode();
//                    ftp.setConnectTimeout(10000);
//                    ftp.setDataTimeout(30000);
//                    ftp.setFileTransferMode(FTP.COMPRESSED_TRANSFER_MODE);
                    ftp.setFileType(FTP.BINARY_FILE_TYPE);
                    return new FTPClientGetFileUtils(ftp);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }


    public static String requestDataByGet(String host, String uri, String username, String password) {
        FTPClient ftp = new FTPClient();
        try {
            ftp.connect(host);
            ftp.login(username, password);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ftp.enterLocalPassiveMode();

        String data = null;
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024)){
            int recon = 0;
            while (recon<5) {
                try {
                    ftp.retrieveFile(uri,outputStream);
                    break;
                }catch (SocketTimeoutException e){
                    e.printStackTrace();
                    recon++;
                }
            }
            return outputStream.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    public BufferedReader getBufferedReader(String uri,long restartOffset){
        FTPClient ftp = getFtpClient();
        try {
            ftp.setRestartOffset(restartOffset);
            InputStream inputStream = ftp.retrieveFileStream(uri);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            return bufferedReader;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public BufferedReader getBufferedReader(String uri){
        return getBufferedReader(uri,0);
    }

    public static String requestDataByGet(BufferedReader bufferedReader,int total){
        return requestDataByGet(bufferedReader,total,"");
    }

    public static String requestDataByGet(BufferedReader bufferedReader,int total,String include){
        int retry = 5;
        StringBuilder stringBuffer = new StringBuilder();
        while (retry-->0){
            try {
                String line;
                while ((line=bufferedReader.readLine())!=null){
                    if (!line.contains(include)) continue;
                    stringBuffer.append(line).append("\n");
                    if(--total<=0){
                        return stringBuffer.toString();
                    }
                }
                if (StringUtils.isEmpty(stringBuffer.toString())) return null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuffer.toString();
    }

    public static void main(String[] args) {

        batch2();
    }

    static void single() {
        String uri = "/20190428/08M0025989_20190428.txt";
        String username = "FAS025989";
        String password = "rhDeezMUHJ221daQ";
        String host = "ftp.fuiou.com";
        long l = System.currentTimeMillis();
        BufferedReader bufferedReader = FTPClientGetFileUtils.create(host, username, password).getBufferedReader(uri, 0);
        String lines;
        int n=0;
        while ((lines = FTPClientGetFileUtils.requestDataByGet(bufferedReader, 100)) != null) {
            System.out.println(lines);
            System.out.println(n++);
        }
        System.out.println("useTime1:"+(System.currentTimeMillis()-l));
    }

    static void batch() {
        String uri = "/20190428/08M0025989_20190428.txt";
        String username = "FAS025989";
        String password = "rhDeezMUHJ221daQ";
        String host = "ftp.fuiou.com";
        FTPClientGetFileUtils ftpClientGetFileUtils = FTPClientGetFileUtils.create(host, username, password);

        FTPFile[] ftpFiles = new FTPFile[0];
        try {
            ftpFiles = ftpClientGetFileUtils.getFtpClient().listFiles(uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        long size = ftpFiles[0].getSize();
        System.out.println(size);
        long l1 = size / 10;
        long l = System.currentTimeMillis();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i =0;i<10;i++){
            int finalI = i;
            new Thread(()->{
                BufferedReader bufferedReader = FTPClientGetFileUtils.create(host, username, password).getBufferedReader(uri, finalI*l1 );
                String lines;

                int n=0;
                int ll = 0;
                while ((lines= FTPClientGetFileUtils.requestDataByGet(bufferedReader, 100))!=null){
                    ll=ll+lines.getBytes().length;
                    System.out.println(lines);
                    System.out.println(n++);
                    if (ll>=l1) break;
                }
                countDownLatch.countDown();
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("useTime2:"+(System.currentTimeMillis()-l));
    }
    static void batch2() {
        String uri = "/20190428/08M0025989_20190428.txt";
        String username = "FAS025989";
        String password = "rhDeezMUHJ221daQ";
        String host = "ftp.fuiou.com";
        FTPClientGetFileUtils ftpClientGetFileUtils = FTPClientGetFileUtils.create(host, username, password);

        FTPFile[] ftpFiles = new FTPFile[0];
        try {
            ftpFiles = ftpClientGetFileUtils.getFtpClient().listFiles(uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        long size = ftpFiles[0].getSize();
        System.out.println(size);
        long l1 = size / 10;
        long l = System.currentTimeMillis();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i =0;i<10;i++){
            int finalI = i;
            new Thread(()->{
                FTPClientGetFileUtils ftpClientGetFileUtils1 = FTPClientGetFileUtils.create(host, username, password);
                FTPClient ftpClient = ftpClientGetFileUtils1.getFtpClient();
                ftpClient.setRestartOffset(finalI*l1);

                byte[] bytes = new byte[1024];
                try {
                    InputStream inputStream = ftpClient.retrieveFileStream(uri);
                    int c = 0;
                    int read;
                    while ((read = inputStream.read(bytes))!=-1){
                        String s = new String(bytes,"UTF-8");
                        System.out.println(s);
                        c =c +read;
                        if (c>=l1){
                            break;
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("useTime2:"+(System.currentTimeMillis()-l));
    }

}
